package com.cmcc.sdtp.client;

import java.io.IOException;
import java.io.InputStream;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.Channels;
import java.nio.channels.ReadableByteChannel;
import java.nio.channels.SocketChannel;
import java.util.Arrays;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

import com.cmcc.sdtp.db.TestPcap;
import com.cmcc.sdtp.sdtp.util.MessageUtil;
import com.cmcc.sdtp.util.SdtpPropertiesUtil;

/**
 * @comments
 * @author B
 * @date 2015-04-10
 * @version 1.0
 */
public class Client {

	private static Logger log = LogManager.getLogger(Client.class);

	// private static final String SERVER_IP = "10.155.21.80";
	// private static final int SERVER_PORT = 2058;
	private static final String SERVER_IP = SdtpPropertiesUtil.getProperty("SERVER_IP");
	private static final int SERVER_PORT = Integer.parseInt(SdtpPropertiesUtil.getProperty("SERVER_PORT"));
	private SocketChannel socketChannel;
	private static final int SOCKET_SO_TIME_OUT = 1000*60*1;
	int recDataInfo = 0;
	
	public static final int verNego_Resp = 0x8001; // 版本协商应答
	public static final int linkAuth_Resp = 0x8002;// 鉴权响应
	public static final int linkCheck_Resp = 0x8003; // 链路检测应答
	public static final int linkRel_Resp = 0x8004; // 连接释放应答
	public static final int XDRRawDataSend_Resp = 0x8006;// XDR对应原始数据传输应答
	public static final int linkDataCheck_Resp = 0x8007;// 链路数据发送校验应答
	public static final int XDRRawDataQuery_Resp = 0x8008;// XDR数据反查应答
	
	public void initSocket() {
		try {
			socketChannel = SocketChannel.open(new InetSocketAddress(SERVER_IP, SERVER_PORT));
			socketChannel.socket().setSoTimeout(SOCKET_SO_TIME_OUT);
		} catch (IOException e) {
			log.error("client.initSocket-error==:", e);
//			e.printStackTrace();
		}
	}

	public void writeMsg(byte[] bytes) {
		try {
			socketChannel.write(ByteBuffer.wrap(bytes));
		} catch (Exception e) {
			log.error("writeMsg,error ", e);
			throw new RuntimeException(e);
		}
	}

	public ByteBuffer readMsg() {
		int totalLength = 0;
		ByteBuffer tempBuffer = null;
		try {
			tempBuffer = ByteBuffer.allocate(2);

			// 设置channel读取时间
			InputStream is = socketChannel.socket().getInputStream();
			ReadableByteChannel readChannel = Channels.newChannel(is);
			int length = readChannel.read(tempBuffer);
			if (length == -1) {
				throw new IOException("client连接异常中断,未从输出流中读取到数据");
			}
			// 获取数据包总长度并构造缓冲区
			totalLength = MessageUtil.toBigInteger(tempBuffer.array()).intValue();

			ByteBuffer tempBuffer2 = ByteBuffer.allocate(totalLength - 2);
			while (tempBuffer2.position() < tempBuffer2.capacity()) {
				length = socketChannel.read(tempBuffer2);
				log.info("数据预计长度: " + tempBuffer2.capacity() + " ,实际长度: " + tempBuffer2.position());
				if (length == -1) {
					if (tempBuffer2.position() != tempBuffer2.capacity()) {
//						log.error("接受数据包长度错误----,预计长度: "+tempBuffer2.capacity()+" ,实际长度: " + tempBuffer2.position());
						throw new IndexOutOfBoundsException("接收数据包长度错误");
					}
				}
			}
//			length = socketChannel.read(tempBuffer2);
			log.info("数据预计长度: " + tempBuffer2.capacity() + " ,实际长度: " + tempBuffer2.position());
			ByteBuffer tempBuffer3 = ByteBuffer.allocate(totalLength);
			tempBuffer3.put(tempBuffer.array());
			tempBuffer3.put(tempBuffer2.array());
			log.info("数据合并成功");
			return tempBuffer3;
		} catch (IOException e) {
			if (totalLength != 0 && tempBuffer != null) {
			}
			throw new RuntimeException(e);
		}
	}

	/**
	 * 关闭流
	 */
	private void release() {
		try {
			if (socketChannel != null) {
				socketChannel.close();
			}
		} catch (IOException e) {
			log.error("client.release-error==:", e);
		}
	}

	/**
	 * @Comments 版本验证请求
	 * @Vsersion: 1.0
	 */
	public boolean verNego_Req() throws Exception {
		boolean b = true;
		try {
			log.info("verNego_Req发起版本验证请求");
			byte[] by = VerNego.verNego_Req();
			log.info("verNego_Req版本验证请求，发送内容长度:" + by.length);
			writeMsg(by);
			log.info("verNego_Req版本验证请求，writeMsg,完成");
			b = this.unpack(readMsg().array());
			log.info("verNego_Req返回值：" + b);
		} catch (Exception e) {
			log.info("verNego_Req请求失败 ", e);
		}
		return b;
	}

	/**
	 * @Comments 版本验证请求
	 * @Vsersion: 1.0
	 */
	public boolean pacaptest() {
		TestPcap p = new TestPcap();
		log.debug("发起pcap测试");
		log.debug("发送内容:" + Arrays.toString(p.test()));
		writeMsg(p.test());
		readMsg();
		return true;
	}

	/**
	 * @Comments 鉴权请求
	 * @Vsersion: 1.0
	 */
	public boolean linkAuth_Req() {
		log.info("linkAuth_Req发起鉴权请求");
//		log.info("发送内容:" + Arrays.toString(linkAuth.linkAuth_Req()));
		writeMsg(LinkAuth.linkAuth_Req());
		log.info("linkAuth_Req发起鉴权请求，writeMsg,完成");
		boolean b = this.unpack(readMsg().array());
		log.info("linkAuth_Req返回值：" + b);
		return b;
	}

	/**
	 * @Comments 链路检测
	 * @Vsersion: 1.0
	 */
	public boolean linkCheck_Req() {
		log.debug("linkCheck_Req发起链路检测请求");
//		log.debug("发送内容:" + Arrays.toString(linkCheck.linkCheck_Req()));
		writeMsg(LinkCheck.linkCheck_Req());
		return this.unpack(readMsg().array());
	}

	/**
	 * @Comments 链路释放请求
	 * @Vsersion: 1.0
	 */
	public void linkRel_Req() {
		log.debug("链路释放请求");
//		log.debug("发送内容:" + Arrays.toString(linkRel.linkRel_Req()));
		writeMsg(LinkRel.linkRel_Req());
		this.unpack(readMsg().array());
		release();
	}

	/**
	 * @Comments 链路数据检测请求
	 * @Vsersion: 1.0
	 */
	public boolean linkDataCheck_Req() {
		log.debug("链路数据检测请求");
		writeMsg(LinkDataCheck.linkDataCheck_Req(recDataInfo));
		return this.unpack(readMsg().array());
	}

	/**
	 * @Comments XDR对应原始数据传输
	 * @Vsersion: 1.0
	 */
	public boolean XDRRawDataSend_Req() {
		recDataInfo++;
		log.debug("XDR对应原始数据传输请求");
		writeMsg(XDRRawDataSend.XDRRawDataSend_Req());
		return this.unpack(readMsg().array());
	}

	/**
	 * @Comments 反查
	 * @Vsersion: 1.0
	 */

	public ByteBuffer XDRRawDataQuery_Req(int i, String s, long l) throws Exception {
		log.info("反查" + s);
		byte[] byteData = XDRRawDataQuery.XDRRawDataQuery_Req(i, s, l);
		log.info("发送内容长度:" + byteData.length);
		writeMsg(byteData);
		return readMsg();
	}

	/**
	 * @Comments 测试
	 * @Vsersion: 1.0
	 */
	public void test(byte[] bytes) {
		writeMsg(bytes);
		readMsg();
	}
	
	public boolean unpack(byte[] byteArray) {
		ByteBuffer buffer = ByteBuffer.wrap(byteArray);
		// 解析信息头，从类型开始长度分别为 2、4、1
		byte[] header = new byte[7];
		buffer.get(header);
		log.info("unpackMessageHeader2(header):"+unpackMessageHeader2(header)+",header=="+header.length);
//		log.info("verNego_Resp:"+verNego_Resp+",linkAuth_Resp:"+linkAuth_Resp);
		// 根据类型选择解析方式
		switch (unpackMessageHeader2(header)) {
		case verNego_Resp:
			log.debug("版本校验响应处理");
			return VerNego.verNego_Resp(buffer);
		case linkAuth_Resp:
			log.debug("鉴权响应处理");
			return LinkAuth.linkAuth_Resp(buffer);
		case linkCheck_Resp:
			// 链路检测就是看你活着没。所以不需要处理
			log.debug("链路检测响应处理");
			return true;
		case linkRel_Resp:
			log.debug("链接释放响应处理");
			return LinkRel.linkRel_Resp(buffer);
		case XDRRawDataSend_Resp:
			log.debug("数据响应处理");
			return true;
		case linkDataCheck_Resp:
			log.debug("链路数据发送校验响应处理");
			return LinkDataCheck.linkDataCheck_Resp(buffer);
		case XDRRawDataQuery_Resp:
			log.debug("数据反查响应处理");
			return XDRRawDataQuery.XDRRawDataQuery_Resp(buffer);
		default:
			log.debug("意义不明");
			return false;
		}
	}
	
	public int unpackMessageHeader2(byte[] header) {
		return Util.unbuildNumericWithSpace2(header, 2);
	}
}